/* list.h - A generic doubly linked list implementation
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * POSSIBILITY OF SUCH DAMAGE.
 */
#include <pthread.h>

#ifndef __DBListIST_H__
#define __DBListIST_H__

#define LL_HIDDEN __attribute__ ((visibility ("hidden")))

/* Node, List, and Iterator are the only data structures used currently. */

#define TRUE 1
#define FALSE 0
#define FAILED -1

#define PARALLELORNOT 150000

typedef enum {
	LL_INCR = 0,
	LL_DECR,
	LL_RAW
} issorted;

typedef struct listNode {
	struct listNode *prev;
	struct listNode *next;
	void *value;
} listNode;

typedef struct listIter {
	listNode *next;
	int direction;
} listIter;

typedef struct list {
	listNode *head;
	listNode *tail;

	issorted sorted;

	pthread_rwlock_t *entity_lock;
	int sort_threads;

	void *(*dup) (void *ptr);
	void (*free) (void *ptr);
	int (*match) (const void *ptr, const void *key);

	unsigned int len;
} list;

/* Functions implemented as macros */
#define listLength(l) ((l)->len)
#define listFirst(l) ((l)->head)
#define listLast(l) ((l)->tail)
#define listPrevNode(n) ((n)->prev)
#define listNextNode(n) ((n)->next)
#define listNodeValue(n) ((n)->value)

#define listSetDupMethod(l,m) ((l)->dup = (m))
#define listSetFreeMethod(l,m) ((l)->free = (m))
#define listSetMatchMethod(l,m) ((l)->match = (m))

#define listGetDupMethod(l) ((l)->dup)
#define listGetFree(l) ((l)->free)
#define listGetMatchMethod(l) ((l)->match)

/* Prototypes */
extern list *listCreate(void);
extern void listRelease(list * list);
extern list *listAddNodeHead(list * list, void *value);
extern list *listAddNodeTail(list * list, void *value);
extern list *listInsertNode(list * list, listNode * old_node, void *value, int after);
extern void listDelNode(list * list, listNode * node);
extern listIter *listGetIterator(list * list, int direction);
extern listNode *listNext(listIter * iter);
extern void listReleaseIterator(listIter * iter);
extern list *listDup(list * orig);
extern listNode *listSearchKey(list * list, void *key);
extern listNode *listIndex(list * list, long index);
extern void listRewind(list * list, listIter * li);
extern void listRewindTail(list * list, listIter * li);
extern void listRotate(list * list);

extern void listSort(list *, int (*cmp) (const void *, const void *));
extern void listQuickSort(listNode *, listNode *, int (*cmp) (const void *, const void *));

/* item less then 100k ,should be used qsort */

extern void list_qsort(list *, int (*cmp) (const void *, const void *));

/* item great then 100k ,should be used psort */
extern void list_psort(list *, int (*cmp) (const void *, const void *));

extern void list_binsert(list *, void *, int (*cmp) (const void *, const void *));
extern void list_bDel_key(list *, void *, int (*cmp) (const void *, const void *));
extern void list_bDel(list *, list *, int (*cmp) (const void *, const void *));

extern list *listDupByKey(list *, void *, int (*cmp) (const void *, const void *));

extern listNode *list_bseek_key(list *, void *, int (*cmp) (const void *, const void *));

/* Directions for iterators */
#define AL_START_HEAD 0
#define AL_START_TAIL 1

#define list_each_from_head(LIST,ITER,NODE) \
        ITER=listGetIterator(LIST,AL_START_HEAD); \
	while ((NODE = listNext(ITER)) != NULL) 

#define list_each_from_tail(LIST,ITER,NODE) \
	ITER=listGetIterator(LIST,AL_START_TAIL); \
	while ((NODE = listNext(ITER)) != NULL) 

#define list_each_end(ITER)  \
   listReleaseIterator(ITER);

#define wlist_each_from_head(LIST,ITER,NODE) \
        while( pthread_rwlock_trywrlock(LIST->entity_lock) != 0 ) ;; \
        ITER=listGetIterator(LIST,AL_START_HEAD); \
        while ((NODE = list_next(ITER)) != NULL) 

#define wlist_each_from_tail(LIST,ITER,NODE) \
        while( pthread_rwlock_trywrlock(LIST->entity_lock) != 0 ) ;; \
        ITER=listGetIterator(LIST,AL_START_TAIL); \
        while ((NODE = list_next(ITER)) != NULL) 

#define rlist_each_from_head(LIST,ITER,NODE) \
        while( pthread_rwlock_tryrdlock(LIST->entity_lock) != 0 ) ;; \
        ITER=listGetIterator(LIST,AL_START_HEAD); \
        while ((NODE = list_next(ITER)) != NULL) 

#define rlist_each_from_tail(LIST,ITER,NODE) \
        while( pthread_rwlock_tryrdlock(LIST->entity_lock) != 0 ) ;; \
        ITER=listGetIterator(LIST,AL_START_TAIL); \
        while ((NODE = list_next(ITER)) != NULL) 

#define llist_each_end(LIST,ITER)  \
        pthread_rwlock_unlock(LIST->entity_lock); \
        list_releaseIterator(ITER);

#endif	  /* __DBListIST_H__ */
